package com.wulis.seckill.common.util;

import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.wulis.seckill.business.pojo.UserInfo;
import com.wulis.seckill.redis.RedisUtils;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

@Component
@AllArgsConstructor
@Slf4j
public class JwtTokenUtil {

    /**
     * token私钥
     */
    @Value("${token.secret:wjx}")
    private String secret;
    /**
     * 令牌有效期（默认60分钟）
     */
    @Value("${token.expireTime:60}")
    private int expireTime;
    protected static final long MILLIS_MINUTE = 60 * 1000L;
    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
    private final RedisUtils redisUtils;

    /**
     * 获取token
     *
     * @param user
     * @return
     */
    public String getToken(UserInfo user) {
        String token = createToken(user);
        //保存到redis
        redisUtils.set(token, token, expireTime, TimeUnit.MINUTES);
        return token;
    }

    /**
     * 创建token
     *
     * @param user
     * @return
     */
    public String createToken(UserInfo user) {
        long expiresAt = System.currentTimeMillis() + expireTime * MILLIS_MINUTE;
        user.setExpireTime(expiresAt);
        //过期时间
        Date date = new Date(expiresAt);
        //私钥及加密算法
        Algorithm algorithm = Algorithm.HMAC256(secret);
        //设置头信息
        HashMap<String, Object> header = new HashMap<>(2);
        header.put("typ", "JWT");
        header.put("alg", "HS256");

        //附带username和userID生成签名
        String token = JWT.create().withHeader(header)
                .withClaim("user", JSONObject.toJSONString(user))
                .withExpiresAt(date)
                .sign(algorithm);
        return token;
    }

    /**
     * 获取登录的用户信息
     *
     * @param token
     * @return
     */
    public UserInfo getUserInfo(String token) {
        UserInfo userInfo = null;
        Object object = redisUtils.get(token);
        if (object != null) {
            userInfo = parseToken(String.valueOf(object));
        }
        return userInfo;
    }

    /**
     * 解析token
     *
     * @param redisToken
     * @return
     */
    public UserInfo parseToken(String redisToken) {
        UserInfo userInfo = null;
        if (StringUtil.isNotEmpty(redisToken)) {
            try {
                JWT.decode(redisToken).getAlgorithm();
                Claim claim = JWT.decode(redisToken).getClaim("user");
                userInfo = JSONObject.parseObject(claim.asString(), UserInfo.class);
            } catch (Exception e) {
                log.warn(e.getMessage());
            }
        }
        return userInfo;
    }

    /**
     * 验证令牌有效期，相差不足20分钟，自动刷新缓存
     *
     * @param token
     */
    public boolean verifyToken(String token) {
        Object o = redisUtils.get(token);
        if (o == null) {
            return false;
        }
        String tokenRedis = String.valueOf(o);
        UserInfo userInfo = parseToken(tokenRedis);
        //判断令牌失效时间是否不足20分钟
        if (userInfo.getExpireTime() - System.currentTimeMillis() <= MILLIS_MINUTE_TEN) {
            //刷新缓存令牌有效期
            refreshToken(token, userInfo);
        }
        return true;
    }

    /**
     * 刷新令牌有效期
     *
     * @param token
     * @param user
     */
    public void refreshToken(String token, UserInfo user) {
        //保存到redis
        redisUtils.set(token, createToken(user), expireTime, TimeUnit.MINUTES);
    }

}
